package com.huanling.main;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.huanling.main.dataflow.DataDeal;
import com.huanling.main.enums.ConflictKeyStrategyEnum;
import com.huanling.main.enums.ReadTypeEnum;
import com.huanling.main.exception.ConflictKeyException;
import com.huanling.main.utils.AlertUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.*;
import javafx.stage.Stage;
import org.apache.commons.collections4.SetUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.collection.CollUtil.emptyIfNull;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.hutool.core.util.StrUtil.EMPTY;
import static com.huanling.main.MainApp.EQUALS_GENERATE;
import static com.huanling.main.MainApp.KEY_GENERATE;
import static com.huanling.main.enums.ConflictKeyStrategyEnum.getConflictKeyDealer;
import static com.huanling.main.utils.FileChooserUtil.buildExcelFileExtensionPairs;
import static com.huanling.main.utils.FileChooserUtil.openFileChooser;

/**
 * 主界面逻辑处理类 -- Control 页面端
 *
 * @author guibosun
 * @since 16 七月 2021
 */
public class MainController {


    @FXML
    public Button originFileBtn;

    @FXML
    public Button anotherFileBtn;

    @FXML
    public Label originFileName;

    @FXML
    public Label anotherFileName;

    private File originFile;

    private File anotherFile;

    private final Set<String> columnSet = new HashSet<>();

    private String firstColumn;

    /**
     * 默认冲突key处理级别
     */
    private ConflictKeyStrategyEnum conflictKeyStrategyEnum = ConflictKeyStrategyEnum.IGNORE;


    @FXML
    public void handlerSubmit(ActionEvent event) {
        if (alertCheck(ObjectUtil.isAllNotEmpty(originFile, anotherFile, firstColumn), "请完成两个文件的输入，之后再提交！")) {
            return;
        }

        List<String> keySelected = getSelectedItems(KEY_GENERATE);
        List<String> equalsSelected = getSelectedItems(EQUALS_GENERATE);
        if (alertCheck(ObjectUtil.isNotEmpty(keySelected), "请选择对比列，之后再提交！")) {
            return;
        }

        DataDeal dataDeal = new DataDeal();
        buildKeySelected(keySelected, dataDeal);
        buildEqualsSelected(equalsSelected, dataDeal);

        try {
            dataDeal.withOriginPath(originFile)
                    .withConflictKeyDealer(getConflictKeyDealer(conflictKeyStrategyEnum))
                    .withComparePath(anotherFile)
                    .withReadTypeEnum(ReadTypeEnum.NORMAL)
                    .withFirstColumn(firstColumn)
                    .withOutputDictionary(originFile.getParent() + File.separator)
                    .deal();
        } catch (ConflictKeyException e) {
            String msg = e.getMsg();
            AlertUtil.create().withAlertType(AlertType.ERROR).withTitle("参照列有误！")
                    .withContentText(msg).buildAndShowWait();
            return;
        } catch (Exception e) {
            AlertUtil.create().withAlertType(AlertType.ERROR).withTitle("出现问题！")
                    .withContentText(e.getMessage()).buildAndShowWait();
            return;
        }
        AlertUtil.create().withAlertType(AlertType.INFORMATION)
                .withContentText("比对完成，结果文件在" + originFile.getParent() + File.separator + "目录下")
                .buildAndShowWait();
    }

    private boolean alertCheck(boolean prediction, String s) {
        if (!prediction) {
            AlertUtil.create().withAlertType(AlertType.WARNING)
                    .withContentText(s)
                    .buildAndShowWait();
            return true;
        }
        return false;
    }

    private void buildEqualsSelected(List<String> equalsSelected, DataDeal dataDeal) {
        if (isNotEmpty(equalsSelected)) {
            dataDeal.withValueEqualsJudge((oldValue, newValue) -> {
                for (String column : equalsSelected) {
                    if (!Objects.equals(oldValue.get(column), newValue.get(column))) {
                        return false;
                    }
                }
                return true;
            });
        } else {
            // 不传对比列默认放弃数据差异比对
            dataDeal.withValueEqualsJudge((oldValue, newValue) -> true);
            dataDeal.withDoDiff(false);
        }
    }

    private void buildKeySelected(List<String> keySelected, DataDeal dataDeal) {
        if (isNotEmpty(keySelected)) {
            dataDeal.withCompareKeyGenerator(stringObjectMap -> keySelected.stream()
                    .map(column -> Objects.isNull(stringObjectMap.get(column)) ? EMPTY : stringObjectMap.get(column).toString())
                    .collect(Collectors.joining("#")));
        }
    }

    private <T> List<T> getSelectedItems(TreeView<T> treeView) {
        return treeView.getRoot().getChildren().stream()
                .map(CheckBoxTreeItem.class::cast)
                .filter(CheckBoxTreeItem::isSelected)
                .map(TreeItem::getValue)
                .map(item -> (T) item)
                .collect(Collectors.toList());
    }


    @FXML
    public void handleOriginFileSelect(ActionEvent actionEvent) {
        Stage primaryStage = MainApp.primaryStage;
        File file = openFileChooser(primaryStage, buildExcelFileExtensionPairs());
        if (Objects.isNull(file)) {
            return;
        }

        KEY_GENERATE.getRoot().getChildren().clear();
        EQUALS_GENERATE.getRoot().getChildren().clear();

        ExcelReader reader = ExcelUtil.getReader(file);
        List<List<Object>> firstRow = reader.read(0, 0);
        Optional<List<String>> strings = Optional.ofNullable(firstRow).filter(item -> !item.isEmpty()).map(item -> item.get(0)).filter(item -> !item.isEmpty())
                .map(item -> item.stream().map(Object::toString).collect(Collectors.toList()));
        if (!strings.isPresent()) {
            AlertUtil.create().withAlertType(AlertType.WARNING)
                    .withContentText("无列名！")
                    .buildAndShowWait();
            return;
        } else {
            originFile = file;
            columnSet.clear();
            columnSet.addAll(strings.get());
            if (!strings.get().isEmpty()) {
                firstColumn = strings.get().get(0);
            }
        }
        if (Objects.nonNull(anotherFile)) {
            anotherFile = null;
            anotherFileName.setText(null);
        }
        originFileName.setText(file.getName());
    }


    @FXML
    public void handleAnotherFileSelect() {
        Stage primaryStage = MainApp.primaryStage;
        if (Objects.isNull(originFile)) {
            AlertUtil.create().withAlertType(AlertType.WARNING)
                    .withContentText("先选择原始文件再选择比对文件！")
                    .buildAndShowWait();
            return;
        }
        File file = openFileChooser(primaryStage, buildExcelFileExtensionPairs());
        if (Objects.isNull(file)) {
            return;
        }


        ExcelReader reader = ExcelUtil.getReader(file);
        List<List<Object>> read = reader.read(0, 0);
        Optional<Set<String>> strings = Optional.ofNullable(read).filter(item -> !item.isEmpty()).map(item -> item.get(0)).filter(item -> !item.isEmpty())
                .map(item -> item.stream().map(Object::toString).collect(Collectors.toSet()));

        if (!strings.isPresent() || !SetUtils.isEqualSet(strings.get(), columnSet)) {
            AlertUtil.create().withAlertType(AlertType.WARNING)
                    .withContentText("两个文件列名不一致！")
                    .buildAndShowWait();
        } else {
            anotherFileName.setText(file.getName());
            anotherFile = file;
            List<CheckBoxTreeItem<String>> treeItemList = emptyIfNull(columnSet).stream().map(item -> {
                CheckBoxTreeItem<String> stringTreeItem = new CheckBoxTreeItem<>();
                stringTreeItem.setValue(item);
                return stringTreeItem;
            }).collect(Collectors.toList());
            KEY_GENERATE.getRoot().getChildren().addAll(treeItemList);
            List<CheckBoxTreeItem<String>> treeItemListCopy = emptyIfNull(columnSet).stream().map(item -> {
                CheckBoxTreeItem<String> stringTreeItem = new CheckBoxTreeItem<>();
                stringTreeItem.setValue(item);
                return stringTreeItem;
            }).collect(Collectors.toList());
            EQUALS_GENERATE.getRoot().getChildren().addAll(treeItemListCopy);
        }
    }

}